#include "unordered_map_me_order_book.h"

#include "matcher/matching_engine.h"

namespace Exchange {
  UnorderedMapMEOrderBook::UnorderedMapMEOrderBook(TickerId ticker_id, Logger *logger, MatchingEngine *matching_engine)
      : ticker_id_(ticker_id), matching_engine_(matching_engine), orders_at_price_pool_(ME_MAX_PRICE_LEVELS), order_pool_(ME_MAX_ORDER_IDS),
        logger_(logger) {
  }

  UnorderedMapMEOrderBook::~UnorderedMapMEOrderBook() {
    logger_->log("%:% %() % OrderBook\n%\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str_),
                toString(false, true));

    matching_engine_ = nullptr;
    bids_by_price_ = asks_by_price_ = nullptr;
  }

  /**
   * @brief 执行订单撤合
   * 
   * 将一个新的主动订单与已存在的被动订单进行撤合，并生成相应的客户端响应和市场数据更新。
   * 根据撤合结果更新被动订单（itr）的状态，如果完全成交则将其从订单簿中移除。
   * 主动订单的剩余数量将通过leaves_qty参数返回。
   * 
   * @param ticker_id 交易品种ID
   * @param client_id 客户端ID，主动订单的客户标识
   * @param side 交易方向，主动订单的买卖方向
   * @param client_order_id 客户端订单ID，主动订单的客户端标识
   * @param new_market_order_id 新的市场订单ID，主动订单的内部标识
   * @param itr 被动订单指针，指向要与主动订单撤合的被动订单
   * @param leaves_qty 输入输出参数，输入主动订单的当前剩余数量，输出撤合后的剩余数量
   */
  auto UnorderedMapMEOrderBook::match(TickerId ticker_id, ClientId client_id, Side side, OrderId client_order_id, OrderId new_market_order_id, MEOrder* itr, Qty* leaves_qty) noexcept {
    // 保存被动订单的引用和原始数量
    const auto order = itr;
    const auto order_qty = order->qty_;
    // 计算成交数量，取主动订单和被动订单数量的最小值
    const auto fill_qty = std::min(*leaves_qty, order_qty);

    // 更新主动订单和被动订单的剩余数量
    *leaves_qty -= fill_qty;
    order->qty_ -= fill_qty;

    // 创建并发送主动订单的成交响应
    client_response_ = {ClientResponseType::FILLED, client_id, ticker_id, client_order_id,
                        new_market_order_id, side, itr->price_, fill_qty, *leaves_qty};
    matching_engine_->sendClientResponse(&client_response_);

    // 创建并发送被动订单的成交响应
    client_response_ = {ClientResponseType::FILLED, order->client_id_, ticker_id, order->client_order_id_,
                        order->market_order_id_, order->side_, itr->price_, fill_qty, order->qty_};
    matching_engine_->sendClientResponse(&client_response_);

    // 创建并发送成交的市场数据更新
    market_update_ = {MarketUpdateType::TRADE, OrderId_INVALID, ticker_id, side, itr->price_, fill_qty, Priority_INVALID};
    matching_engine_->sendMarketUpdate(&market_update_);

    // 如果被动订单完全成交，则从订单簿中移除
    if (!order->qty_) {
      // 创建并发送被动订单取消的市场数据更新
      market_update_ = {MarketUpdateType::CANCEL, order->market_order_id_, ticker_id, order->side_,
                        order->price_, order_qty, Priority_INVALID};
      matching_engine_->sendMarketUpdate(&market_update_);

      // 从订单簿中移除被动订单，并记录性能指标
      START_MEASURE(Exchange_UnorderedMapMEOrderBook_removeOrder);
      removeOrder(order);
      END_MEASURE(Exchange_UnorderedMapMEOrderBook_removeOrder, (*logger_));
    } else {
      // 如果被动订单部分成交，则发送修改的市场数据更新
      market_update_ = {MarketUpdateType::MODIFY, order->market_order_id_, ticker_id, order->side_,
                        order->price_, order->qty_, order->priority_};
      matching_engine_->sendMarketUpdate(&market_update_);
    }
  }

  /**
   * @brief 检查新订单是否可与已存在的被动订单撤合
   * 
   * 检查具有指定属性的新订单是否可以与订单簿中对手方的被动订单进行撤合。
   * 如果可以撤合，则调用match()方法执行撤合操作，并返回新订单的剩余数量。
   * 这个方法是实现价格-时间优先撤合算法的关键部分。
   * 
   * @param client_id 客户端ID，新订单的客户标识
   * @param client_order_id 客户端订单ID，新订单的客户端标识
   * @param ticker_id 交易品种ID
   * @param side 交易方向，新订单的买卖方向
   * @param price 价格，新订单的限价
   * @param qty 数量，新订单的数量
   * @param new_market_order_id 新的市场订单ID，新订单的内部标识
   * @return 新订单的剩余数量，如果完全成交则为0
   */
  auto UnorderedMapMEOrderBook::checkForMatch(ClientId client_id, OrderId client_order_id, TickerId ticker_id, Side side, Price price, Qty qty, Qty new_market_order_id) noexcept {
    // 初始化剩余数量为订单原始数量
    auto leaves_qty = qty;

    // 如果是买单，则与卖盘中的订单进行撤合
    if (side == Side::BUY) {
      // 当还有剩余数量并且卖盘不为空时继续撤合
      while (leaves_qty && asks_by_price_) {
        // 获取卖盘最优价格水平的第一个订单
        const auto ask_itr = asks_by_price_->first_me_order_;
        // 如果买单价格低于卖盘最优价格，则无法撤合，退出循环
        if (LIKELY(price < ask_itr->price_)) {
          break;
        }

        // 调用match方法执行撤合，并记录性能指标
        START_MEASURE(Exchange_UnorderedMapMEOrderBook_match);
        match(ticker_id, client_id, side, client_order_id, new_market_order_id, ask_itr, &leaves_qty);
        END_MEASURE(Exchange_UnorderedMapMEOrderBook_match, (*logger_));
      }
    }
    // 如果是卖单，则与买盘中的订单进行撤合
    if (side == Side::SELL) {
      // 当还有剩余数量并且买盘不为空时继续撤合
      while (leaves_qty && bids_by_price_) {
        // 获取买盘最优价格水平的第一个订单
        const auto bid_itr = bids_by_price_->first_me_order_;
        // 如果卖单价格高于买盘最优价格，则无法撤合，退出循环
        if (LIKELY(price > bid_itr->price_)) {
          break;
        }

        // 调用match方法执行撤合，并记录性能指标
        START_MEASURE(Exchange_UnorderedMapMEOrderBook_match);
        match(ticker_id, client_id, side, client_order_id, new_market_order_id, bid_itr, &leaves_qty);
        END_MEASURE(Exchange_UnorderedMapMEOrderBook_match, (*logger_));
      }
    }

    // 返回订单的剩余数量
    return leaves_qty;
  }

  /**
   * @brief 创建并添加新订单到订单簿
   * 
   * 根据提供的属性创建新订单并添加到订单簿中。
   * 会检查新订单是否与现有的对手方订单匹配，如果匹配则执行撤合。
   * 如果订单未完全成交，剩余部分将作为被动订单添加到订单簿中。
   * 
   * @param client_id 客户端ID，标识下单的客户
   * @param client_order_id 客户端订单ID，客户端用于标识订单的唯一标识符
   * @param ticker_id 交易品种ID，标识订单所交易的品种
   * @param side 交易方向（买/卖），标识订单是买单还是卖单
   * @param price 价格，订单的限价
   * @param qty 数量，订单的数量
   */
  auto UnorderedMapMEOrderBook::add(ClientId client_id, OrderId client_order_id, TickerId ticker_id, Side side, Price price, Qty qty) noexcept -> void {
    // 生成新的市场订单ID
    const auto new_market_order_id = generateNewMarketOrderId();
    // 创建并发送订单接受的客户端响应
    client_response_ = {ClientResponseType::ACCEPTED, client_id, ticker_id, client_order_id, new_market_order_id, side, price, 0, qty};
    matching_engine_->sendClientResponse(&client_response_);

    // 检查新订单是否可与现有被动订单撤合，并记录性能指标
    START_MEASURE(Exchange_UnorderedMapMEOrderBook_checkForMatch);
    const auto leaves_qty = checkForMatch(client_id, client_order_id, ticker_id, side, price, qty, new_market_order_id);
    END_MEASURE(Exchange_UnorderedMapMEOrderBook_checkForMatch, (*logger_));

    // 如果订单有剩余数量，则将其添加到订单簿中作为被动订单
    if (LIKELY(leaves_qty)) {
      // 获取该价格水平的下一个优先级
      const auto priority = getNextPriority(price);

      // 从内存池中分配新订单对象
      auto order = order_pool_.allocate(ticker_id, client_id, client_order_id, new_market_order_id, side, price, leaves_qty, priority, nullptr,
                                        nullptr);
      START_MEASURE(Exchange_UnorderedMapMEOrderBook_addOrder);
      // 将订单添加到订单簿中
      addOrder(order);
      END_MEASURE(Exchange_UnorderedMapMEOrderBook_addOrder, (*logger_));

      // 创建并发送订单添加的市场数据更新
      market_update_ = {MarketUpdateType::ADD, new_market_order_id, ticker_id, side, price, leaves_qty, priority};
      matching_engine_->sendMarketUpdate(&market_update_);
    }
  }

  /**
   * @brief 尝试取消订单簿中的订单
   * 
   * 根据客户端ID和订单ID查找并取消订单。
   * 如果订单不存在，会发出取消拒绝响应。
   * 成功取消的订单会从订单簿中移除，并发送相应的市场数据更新和客户端响应。
   * 
   * @param client_id 客户端ID，标识下单的客户
   * @param order_id 订单ID，客户端用于标识订单的唯一标识符
   * @param ticker_id 交易品种ID，标识订单所交易的品种
   */
  auto UnorderedMapMEOrderBook::cancel(ClientId client_id, OrderId order_id, TickerId ticker_id) noexcept -> void {
    // 检查客户端ID是否有效
    auto is_cancelable = (client_id < cid_oid_to_order_.size());

    MEOrder *exchange_order = nullptr;
    if (LIKELY(is_cancelable)) {
      // 获取客户的订单映射
      auto &co_itr = cid_oid_to_order_[client_id];
      // 查找要取消的订单
      exchange_order = co_itr[order_id];
      // 检查订单是否存在
      is_cancelable = (exchange_order != nullptr);
    }

    if (UNLIKELY(!is_cancelable)) {
      // 如果订单不存在或无法取消，创建取消拒绝的客户端响应
      client_response_ = {ClientResponseType::CANCEL_REJECTED, client_id, ticker_id, order_id, OrderId_INVALID,
                          Side::INVALID, Price_INVALID, Qty_INVALID, Qty_INVALID};
    } else {
      // 如果订单存在且可取消，创建取消成功的客户端响应
      client_response_ = {ClientResponseType::CANCELED, client_id, ticker_id, order_id, exchange_order->market_order_id_,
                          exchange_order->side_, exchange_order->price_, Qty_INVALID, exchange_order->qty_};
      // 创建取消订单的市场数据更新
      market_update_ = {MarketUpdateType::CANCEL, exchange_order->market_order_id_, ticker_id, exchange_order->side_, exchange_order->price_, 0,
                        exchange_order->priority_};

      // 从订单簿中移除订单，并记录性能指标
      START_MEASURE(Exchange_UnorderedMapMEOrderBook_removeOrder);
      removeOrder(exchange_order);
      END_MEASURE(Exchange_UnorderedMapMEOrderBook_removeOrder, (*logger_));

      // 发送市场数据更新
      matching_engine_->sendMarketUpdate(&market_update_);
    }

    // 发送客户端响应
    matching_engine_->sendClientResponse(&client_response_);
  }

  /**
   * @brief 将订单簿转换为字符串表示
   * 
   * 生成订单簿的文本表示，包括买卖盘的所有价格水平和订单。
   * 可用于日志记录、调试和状态监控。
   * 
   * @param detailed 是否包含详细信息，如果为true则包含每个订单的详细信息
   * @param validity_check 是否执行有效性检查，验证订单簿的内部一致性
   * @return 订单簿的字符串表示
   */
  auto UnorderedMapMEOrderBook::toString(bool detailed, bool validity_check) const -> std::string {
    std::stringstream ss;
    std::string time_str;

    // 定义一个lambda函数，用于打印价格水平及其包含的订单
    auto printer = [&](std::stringstream &ss, MEOrdersAtPrice *itr, Side side, Price &last_price, bool sanity_check) {
      char buf[4096];
      Qty qty = 0;
      size_t num_orders = 0;

      // 计算该价格水平的总数量和订单数
      for (auto o_itr = itr->first_me_order_;; o_itr = o_itr->next_order_) {
        qty += o_itr->qty_;
        ++num_orders;
        if (o_itr->next_order_ == itr->first_me_order_)
          break;
      }
      // 格式化输出价格水平信息：当前价格、前一个价格、后一个价格、总数量和订单数
      sprintf(buf, " <px:%3s p:%3s n:%3s> %-3s @ %-5s(%-4s)",
              priceToString(itr->price_).c_str(), priceToString(itr->prev_entry_->price_).c_str(), priceToString(itr->next_entry_->price_).c_str(),
              priceToString(itr->price_).c_str(), qtyToString(qty).c_str(), std::to_string(num_orders).c_str());
      ss << buf;
      // 如果需要详细信息，则遍历并打印该价格水平的每个订单
      for (auto o_itr = itr->first_me_order_;; o_itr = o_itr->next_order_) {
        if (detailed) {
          // 格式化输出订单信息：订单ID、数量、前一个订单ID、后一个订单ID
          sprintf(buf, "[oid:%s q:%s p:%s n:%s] ",
                  orderIdToString(o_itr->market_order_id_).c_str(), qtyToString(o_itr->qty_).c_str(),
                  orderIdToString(o_itr->prev_order_ ? o_itr->prev_order_->market_order_id_ : OrderId_INVALID).c_str(),
                  orderIdToString(o_itr->next_order_ ? o_itr->next_order_->market_order_id_ : OrderId_INVALID).c_str());
          ss << buf;
        }
        if (o_itr->next_order_ == itr->first_me_order_)
          break;
      }

      ss << std::endl;

      // 如果需要进行有效性检查，则验证价格水平的排序是否正确
      if (sanity_check) {
        // 卖盘应按价格升序排列，买盘应按价格降序排列
        if ((side == Side::SELL && last_price >= itr->price_) || (side == Side::BUY && last_price <= itr->price_)) {
          FATAL("Bids/Asks not sorted by ascending/descending prices last:" + priceToString(last_price) + " itr:" + itr->toString());
        }
        last_price = itr->price_;
      }
    };

    // 输出交易品种ID
    ss << "Ticker:" << tickerIdToString(ticker_id_) << std::endl;
    {
      // 首先处理卖盘（asks）
      auto ask_itr = asks_by_price_; // 卖盘的第一个价格水平
      auto last_ask_price = std::numeric_limits<Price>::min(); // 初始化为最小价格，用于有效性检查
      // 遍历卖盘的所有价格水平
      for (size_t count = 0; ask_itr; ++count) {
        ss << "ASKS L:" << count << " => "; // 输出卖盘层级标识
        // 确定下一个要访问的价格水平，如果已经到达链表头部则设置为nullptr
        auto next_ask_itr = (ask_itr->next_entry_ == asks_by_price_ ? nullptr : ask_itr->next_entry_);
        // 调用前面定义的lambda函数打印当前价格水平的信息
        printer(ss, ask_itr, Side::SELL, last_ask_price, validity_check);
        ask_itr = next_ask_itr; // 移动到下一个价格水平
      }
    }

    // 输出分隔线，分隔卖盘和买盘
    ss << std::endl << "                          X" << std::endl << std::endl;

    {
      // 然后处理买盘（bids）
      auto bid_itr = bids_by_price_; // 买盘的第一个价格水平
      auto last_bid_price = std::numeric_limits<Price>::max(); // 初始化为最大价格，用于有效性检查
      // 遍历买盘的所有价格水平
      for (size_t count = 0; bid_itr; ++count) {
        ss << "BIDS L:" << count << " => "; // 输出买盘层级标识
        // 确定下一个要访问的价格水平，如果已经到达链表头部则设置为nullptr
        auto next_bid_itr = (bid_itr->next_entry_ == bids_by_price_ ? nullptr : bid_itr->next_entry_);
        // 调用前面定义的lambda函数打印当前价格水平的信息
        printer(ss, bid_itr, Side::BUY, last_bid_price, validity_check);
        bid_itr = next_bid_itr; // 移动到下一个价格水平
      }
    }

    return ss.str();
  }
}
